package com.youlai.boot.excel;

import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;
import java.util.Objects;

/**
 * 模板填充单元格合并handler
 *
 * @author lixisheng
 */
public class ExcelFillMergeHandler implements RowWriteHandler {

    /**
     * 合并列结合索引
     */
    private List<Integer> fieldList;

    /**
     * fieldList中的列是否需要合并的列，这里处理是为了方便代码中需要排除的列过多，则写合并的列
     */
    private Boolean needMeger;

    private Integer standIndex;

    private Integer headRow;

    public ExcelFillMergeHandler(List<Integer> fieldList, Boolean needMeger, Integer standIndex, Integer headRow) {
        this.fieldList = fieldList;
        this.headRow = headRow;
        this.standIndex = standIndex;
        this.needMeger = needMeger;
    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        //校验 如果是表头，不做处理
        if (isHead) {
            return;
        }
        if (relativeRowIndex == null) {
            return;
        }
        //校验 如果是第一行数据，不做处理
        if (relativeRowIndex < 1) {
            return;
        }

        Sheet sheet = row.getSheet();
        int currRelativeRowIndex = row.getRowNum();
        int prevRelativeRowIndex = currRelativeRowIndex - 1;
        Row prevRow = sheet.getRow(prevRelativeRowIndex);
        if (Objects.isNull(prevRow)) {
            // TODO 为空时 从缓存取 上一行的数据
            sheet = writeSheetHolder.getCachedSheet();
            prevRow = sheet.getRow(prevRelativeRowIndex);
            if (Objects.isNull(prevRow)) {
                sheet = writeSheetHolder.getSheet();
                prevRow = sheet.getRow(prevRelativeRowIndex);
                if (Objects.isNull(prevRow)) {
                    return;
                }
            }
        }

        if (needMeger) {
            for (Integer idx : fieldList) {
                Cell currStandRowCell = row.getCell(standIndex);
                Cell prevStandRowCell = prevRow.getCell(standIndex);
                //相同标准合并
                Object currStandObj = getCellValue(currStandRowCell);
                Object prevStrandObj = getCellValue(prevStandRowCell);
                if (!Objects.equals(currStandObj, prevStrandObj)) {
                    break;
                }

                doMergeCell(sheet, row, currRelativeRowIndex, prevRow, prevRelativeRowIndex, idx);
            }
        } else {
            short lastCellNum = prevRow.getLastCellNum();
            for (int idx = 0; idx < lastCellNum; idx++) {
                if (fieldList.contains(idx)) {
                    continue;
                }
                Cell currStandRowCell = row.getCell(standIndex);
                Cell prevStandRowCell = prevRow.getCell(standIndex);
                //相同标准合并
                Object currStandObj = getCellValue(currStandRowCell);
                Object prevStrandObj = getCellValue(prevStandRowCell);
                if (!Objects.equals(currStandObj, prevStrandObj)) {
                    break;
                }
                doMergeCell(sheet, row, currRelativeRowIndex, prevRow, prevRelativeRowIndex, idx);
            }
        }
    }

    public void doMergeCell(Sheet sheet, Row currRow, int currRelativeRowIndex, Row prevRow, int prevRelativeRowIndex, int idx) {
        Cell currCell;
        Cell prevCell;
        currCell = currRow.getCell(idx);
        prevCell = prevRow.getCell(idx);
        Object currObj = getCellValue(currCell);
        Object prevObj = getCellValue(prevCell);

        if (!Objects.equals(currObj, prevObj)) {
            return;
        }
        mergeCell(sheet, currRelativeRowIndex, prevRelativeRowIndex, currCell);
    }

    public void mergeCell(Sheet sheet, Integer currRowIndex, Integer prevRowIndex, Cell cell) {
        int numMergedRegions = sheet.getNumMergedRegions();
        boolean isMerge = false;
        int mergedRegionSize = numMergedRegions - 100;
        if (mergedRegionSize < 0) {
            mergedRegionSize = -1;
        }
        for (int i = numMergedRegions - 1; i > mergedRegionSize; i--) {
            CellRangeAddress cellAddress = sheet.getMergedRegion(i);
            if (cellAddress.isInRange(prevRowIndex, cell.getColumnIndex())) {
                sheet.removeMergedRegion(i);//移除合并单元格
                cellAddress.setLastRow(currRowIndex);//设置当前的合并策略的最后行数
                //sheet.addMergedRegion(cellAddress);
                sheet.addMergedRegionUnsafe(cellAddress);
                isMerge = true;
                break;
            }
        }
        if (!isMerge) {
            CellRangeAddress cellAddress = new CellRangeAddress(prevRowIndex, currRowIndex, cell.getColumnIndex(), cell.getColumnIndex());
//            sheet.addMergedRegion(cellAddress);
            sheet.addMergedRegionUnsafe(cellAddress);
        }
    }

    public Object getCellValue(Cell cell) {
        if (Objects.isNull(cell)) {
            return null;
        }
        CellType cellType = cell.getCellType();
        switch (cellType) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return cell.getNumericCellValue();
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case ERROR:
                return cell.getErrorCellValue();
            default:
                return null;
        }
    }
}
